개발이 끝나면 바로 출시해야 할까
클라이언트 개발은 끝났는데 백엔드 API는 아직 준비되지 않았다고 해보자.
개발이 모두 끝나더라도 마케팅이나 이벤트 일정 때문에 공개를 기다려야 할 수 있다.
그때마다 작업 브랜치를 오래 유지하면 다른 작업과 충돌할 가능성이 커진다.
모바일 앱에는 스토어 심사에 걸리는 시간도 있다.
Android와 iPhone 앱을 동시에 제출해도 같은 날 심사가 끝난다는 보장은 없다.
| 스토어 | 공식 안내 기준 심사·처리 시간 |
|---|---|
| Google Play | 몇 시간에서 최대 7일, 예외적으로 그 이상. 제출부터 게시까지 최소 1주일의 여유를 권장 |
| App Store | 평균적으로 제출 건의 90%를 24시간 이내에 심사. 반려나 추가 확인으로 지연될 수 있음 |
2026년 9월 확인한 공식 안내이며, 사용자의 설치 완료까지 걸리는 시간은 아니다. Google Play — 검토 및 게시 시점 관리, Apple — App Review
그래서 코드를 전달하는 시점과 사용자가 기능을 쓰기 시작하는 시점을 나눈다.
| 구분 | 의미 |
|---|---|
| 배포(Deployment) | 새 기능이 포함된 앱 버전을 전달하는 것 |
| 출시(Release) | 사용자가 해당 기능을 이용할 수 있게 공개하는 것 |
새 기능을 OFF 상태로 미리 배포하고, 양쪽 앱과 백엔드가 준비되면 활성화할 수 있다.
다만 사용자가 앱을 업데이트해야 새 코드가 기기에 도달하므로, 구버전 앱에 없는 기능까지 켤 수는 없다.
Feature Flag란 무엇인가
Feature Flag는 코드를 다시 배포하지 않고 설정에 따라 기능의 동작을 선택할 수 있게 하는 장치다.
홈에 새로운 추천 영역을 추가했다면, Flag가 ON일 때는 새 영역을 보여주고 OFF일 때는 기존 홈을 보여준다.
여기서는 ON/OFF로 설명하지만, 설정값이 Boolean으로만 제한되는 것은 아니다.
배포와 출시를 분리하는 가치
- 개발 일정 분리: 클라이언트가 먼저 끝나면 비활성 상태로 배포하고 다음 작업을 진행할 수 있다.
- 비즈니스 일정 분리: 마케팅이나 이벤트 시작일에 맞춰 기능을 공개할 수 있다.
- 점진적 공개: 내부 사용자부터 일부 사용자, 전체 사용자로 대상을 넓힐 수 있다.
- 장애 대응: 문제가 생기면 새 기능을 끄고 기존 기능으로 전환할 수 있다.
외부 일정 때문에 완료된 코드를 오래 보관할 필요가 줄어든다.
다만 코드 배포를 기다리게 하던 의존성을 기능 활성화 조건으로 옮기는 것이므로, 공개 전에는 백엔드와 관련 작업이 준비되어야 한다.
OFF 상태로 배포하기 전에 확인할 것
버튼만 숨겨도 백그라운드 작업이나 딥링크를 통해 새 로직이 실행될 수 있다.
실제 Flag 분기와 최종 API를 함께 검증해야 한다.
| 상태 | 확인할 내용 |
|---|---|
| OFF | 기존 기능이 유지되고 준비되지 않은 API를 호출하지 않는가 |
| ON | Mock이 아닌 최종 API와 정상 동작하는가 |
| 설정 조회 실패 | 정해둔 fallback으로 동작하는가 |
| 실행 중 설정 변경 | 진행 중인 화면과 작업이 어긋나지 않는가 |
클라이언트가 새 백엔드 기능에 의존한다면 서버를 먼저 준비하고 검증한 뒤 클라이언트 노출을 연다.
Flag를 끄더라도 이미 실행된 작업이나 저장된 데이터까지 되돌아가지는 않는다.
Feature Flag 기능 요구사항
누구에게 제공하고, 언제 적용하며, 실패하면 어떻게 동작할지를 정해야 한다.
| 요구사항 | 정해야 할 내용 |
|---|---|
| 환경 분리 | QA와 프로덕션의 설정 구분 |
| 대상 지정 | 사용자 ID, 앱 버전, 내부 사용자 여부 등의 조건 |
| fallback | 설정이 없거나 조회에 실패했을 때의 기본 동작 |
| 캐시와 적용 시점 | 설정을 언제 갱신하고 화면에 반영할지 |
| 공통 사용 | Presentation과 Domain에서 같은 기준으로 조회 |
fallback
fallback은 설정을 정상적으로 얻지 못했을 때 사용자에게 제공할 동작이다.
새 추천 영역에 문제가 생겼다면 기존 추천을 보여주거나 해당 영역을 숨길 수 있다.
기능별로 기본 동작을 정하고, 정상적인 OFF와 조회 실패를 구분해 기록한다.
설정 적용 시점
사용자가 입력 중일 때 설정이 바뀌어 화면이 교체되면 흐름이 끊길 수 있다.
새 설정은 다음 화면 진입처럼 안전한 시점에 적용하도록 정한다. Firebase — 설정 로딩 전략
캐시나 오프라인 상태 때문에 긴급 OFF가 모든 기기에 즉시 반영되지는 않을 수 있다.
A/B Test는 무엇을 검증하는가
새 추천 화면을 출시한 뒤 클릭이 늘었다고 해보자.
새 화면의 효과일 수도 있지만, 같은 기간에 진행한 이벤트 때문일 수도 있다.
A/B Test는 사용자를 무작위로 나누어 서로 다른 시안을 같은 기간에 제공하고, 사전에 정한 지표를 비교하는 실험이다.
보통 A는 기존 동작인 대조군, B는 새 동작인 실험군이며 A/B/C처럼 여러 시안을 비교할 수도 있다.
| 구분 | Feature Flag | A/B Test |
|---|---|---|
| 핵심 질문 | 누구에게 어떤 기능을 열 것인가 | 어떤 시안이 목표 지표를 개선하는가 |
| 필요한 것 | 조건 평가와 기본 동작 | 그룹 배정, 노출·행동 기록, 결과 분석 |
Feature Flag로 실험 시안을 제공할 수 있지만, 화면을 나누어 보여주는 것만으로는 부족하다.
배정과 측정, 분석이 연결되어야 한다.
먼저 가설과 지표를 정한다
추천 화면을 바꾼다면 다음처럼 가설을 세울 수 있다.
추천 코스의 정보를 자세히 보여주면, 사용자가 자신에게 맞는 코스를 찾아 저장할 확률이 높아질 것이다.
개선하려는 지표와 악화되어서는 안 되는 지표를 함께 정한다.
| 구분 | 예 |
|---|---|
| 주 지표 | 정해진 기간 안에 코스를 저장한 사용자 비율 |
| 보조 지표 | 추천 영역 클릭률, 상세 페이지 진입률 |
| 보호 지표(Guardrail) | 크래시율, 홈 로딩 시간, 이탈률 |
비율을 계산할 대상도 미리 정해야 한다.
클릭한 사용자만 골라 비교하면 시안에 따라 분석 대상이 달라져 결과가 왜곡될 수 있다.
토스의 푸시 실험도 CTR과 함께 활성 사용자·매출을 보호 지표로 관찰했다. 토스 — A/B Test 사례
A/B Test 기능 요구사항
| 요구사항 | 정해야 할 내용 |
|---|---|
| 실험 대상 | 어떤 사용자에게 실험을 진행할지 |
| 시안과 배정 비율 | A/B/C 중 무엇을 어떤 비율로 제공할지 |
| 배정 유지 | 같은 사용자가 같은 시안을 경험하도록 할 기준 |
| fallback | 평가 실패 시 제공할 기본 시안과 실패 기록 |
| 공통 사용 | Presentation과 Domain에서 같은 배정 결과 사용 |
| 측정 | 실제 노출과 목표 행동을 연결하는 로그 |
실험 대상과 배정 비율
먼저 실험 대상을 정하고, 그 안에서 그룹을 나눈다.
사용자의 20%를 실험 대상으로 삼고 A와 B에 절반씩 배정하면, 전체의 약 10%씩 각 시안을 보게 된다.
반드시 50:50이어야 하는 것은 아니며, 실험 목적에 맞춰 비율을 정할 수 있다.
같은 사용자에게 같은 시안 제공하기
화면을 열 때마다 새로 배정하면 한 사용자가 A와 B를 번갈아 보게 된다.
이를 막기 위해 실험 ID와 사용자 식별자를 해시해 일관된 그룹에 배정할 수 있다. 결정적 버킷 배정 방식
일반적인 사용자 단위 실험에서는 실험 기간 동안 배정을 유지하는 것을 기본으로 한다.
홈에서 A를 보고 상세 화면에서 B로 바뀌면, 저장 행동이 어느 시안의 영향을 받았는지 판단하기 어려워진다.
배정, 노출, 전환을 구분한다
[0009 - 로깅](/blog/0009 - 로깅/)에서 정리한 비즈니스 메트릭 로깅이 여기서 필요하다.
| 단계 | 의미 | 예 |
|---|---|---|
| 배정 | 어떤 시안을 제공할지 결정 | 추천 화면 B에 배정 |
| 노출 | 시안이 실제 사용자 경험에 적용 | B 추천 영역이 표시됨 |
| 전환 | 목표 행동이 발생 | 추천 코스를 저장 |
설정값을 읽었다고 사용자가 기능을 봤다고 판단해서는 안 된다.
홈 아래쪽의 추천 영역까지 스크롤하지 않았다면 실제 UI 노출은 없을 수 있다.
로그에는 실험 ID, 적용한 시안, 분석용 사용자 식별자, 이벤트와 시각을 남겨 노출과 전환을 연결한다.
Compose 재구성 등으로 같은 노출을 중복 기록하지 않도록 주의한다.
결과는 어떻게 판단할까
전환율이 A는 10%, B는 11%라면 B가 1%p 높고, 상대적으로 10% 개선된 것이다.
하지만 표본이 적다면 우연한 차이일 수 있다.
- 시작 전에 필요한 표본 수, 실험 기간, 중단 기준을 정한다.
- 진행 중에는 로그 누락과 크래시·성능 같은 보호 지표를 확인한다.
- 종료 후에는 차이가 우연인지, 실제 개선 폭이 의미 있는지, 보호 지표가 악화되지 않았는지 함께 판단한다.
수치가 잠깐 좋아졌다는 이유만으로 실험을 끝내거나 전체 출시를 결정하지 않는다. Microsoft — 실험 운영 가이드
Presentation과 Domain에서 함께 사용하기
홈 추천 기능을 기준으로 책임을 나누면 다음과 같다.
아래는 특정 SDK에 종속되지 않는 설계 예시다.
| 구성 요소 | 맡는 책임 |
|---|---|
| FeatureFlagReader | 기능 활성화 여부 제공 |
| ExperimentReader | 실험 참여 여부와 시안 제공 |
| Data 계층 | 원격 설정 조회, 캐시와 fallback 처리 |
| UseCase / ViewModel | 결정값을 데이터 조회와 화면 상태에 전달 |
| Presentation | 결정에 맞는 UI 표시와 실제 노출 기록 |
Domain에는 SDK 타입 대신 앱에서 사용하는 인터페이스와 모델을 두고, Data 계층에서 구현한다.
Feature Flag의 노출 여부는 Boolean으로 표현할 수 있지만, A/B Test는 여러 시안과 미참여·평가 실패 상태를 구분해야 한다.
평가 실패로 기존 화면을 보여줬다고 정상 대조군으로 기록해서는 안 된다.
한 흐름에서 확보한 결정값을 데이터 조회, 화면 표시, 전환 로그에 함께 사용한다.
Domain과 Presentation이 각각 다시 조회해 다른 시안을 적용하는 일을 막기 위해서다.
두 기능을 함께 쓴다면 Flag가 OFF일 때는 기존 기능을 제공하고, ON일 때 실험 시안을 판단하는 식으로 우선순위를 정한다.
출시 후에는 분기를 정리한다
실험을 끝내고 전체 공개했다면 불필요한 Flag와 이전 시안의 코드를 제거한다.
분기가 쌓일수록 검증해야 할 조합과 유지보수 비용도 늘어난다.
다만 구버전 앱이 사용하는 원격 설정과 API는 호환성을 확인한 뒤 정리해야 한다.